package tcln.gxtx.client.widget.grid.renderer.html;

import tcln.gxtx.client.utils.lang.GwtStringUtils;
import tcln.gxtx.client.widget.treegrid.AbstractTreeGrid;
import tcln.gxtx.client.widget.treegrid.model.AbstractTreeModel;

import com.extjs.gxt.ui.client.core.XDOM;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.Grid;

/**
 * A composit renderer which composes of 2 HTML renderer: one in the left and the other in the right. The layout used
 * for this rendering is {@link com.extjs.gxt.ui.client.widget.layout.BorderLayout}.
 * <p>
 * <b>Important note</b>: There is a special requirement for this renderer. Because of the nature of
 * {@link CheckboxHtmlGridCellRenderer} , a small CSS class must be created if {@link CheckboxHtmlGridCellRenderer} is
 * used. It must be 'x-form-check-wrap', which should be similar to:
 * 
 * <pre>
 * &#64;external x-form-check-wrap, x-border-layout-ct;
 * [...]
 * .tree-grid .x-form-check-wrap {
 *     border: none;
 *     padding: 2px;
 *     height: 14px;
 *     background: none;
 *     border-width: 0px;
 *     text-align: center;
 * }
 * </pre>
 * 
 * @param <M>
 * @author Truong Chau Lien Ngoc (lienngoc@gmail.com)
 */
public class TwoComponentHtmlRenderer<M extends AbstractTreeModel> implements HtmlGridCellRenderer<M> {

    static final int MAX_PERCENTAGE_VALUE = 100;
    static final int DEFAULT_LEFT_REGION_SIZE = 30;

    Integer width;
    Integer height;
    Integer leftRegionSize;
    ColumnConfig ownerColumn;
    AbstractTreeGrid<M> ownerTree;

    HtmlGridCellRenderer<M> leftRenderer;
    HtmlGridCellRenderer<M> rightRenderer;

    /**
     * @param ownerColumn
     */
    public TwoComponentHtmlRenderer(ColumnConfig ownerColumn) {
        this.ownerColumn = ownerColumn;
    }

    /**
     * Sets the owner column of this renderer.
     * 
     * @param ownerColumn
     *            the new ownerColumn to set
     */
    public void setOwnerColumn(ColumnConfig ownerColumn) {
        this.ownerColumn = ownerColumn;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ColumnConfig getOwnerColumn() {
        return ownerColumn;
    }

    /**
     * Sets custom width for this renderer. By default (i.e. the {@link #width} is not specified), the owner column's
     * width is used.
     * 
     * @param width
     *            the new width to set
     */
    public void setWidth(Integer width) {
        this.width = width;
    }

    /**
     * Returns current renderer's width.
     * 
     * @return the width.
     */
    public Integer getWidth() {
        if (width == null) {
            width = ownerColumn.getWidth();
        }
        return width;
    }

    /**
     * Sets custom height for this renderer. By default (i.e. the {@link #height} is not specified), the row height is
     * used.
     * 
     * @param height
     *            the new height to set
     */
    public void setHeight(Integer height) {
        this.height = height;
    }

    /**
     * Returns current renderer's height.
     * 
     * @return the height.
     */
    public Integer getHeight() {
        if (height == null) {
            height = ownerTree.getRowHeight();
        }
        return height;
    }

    /**
     * Sets width for the left region. The right region is always fill-up the remaining space of this renderer.
     * 
     * @param leftRegionSize
     *            the new leftRegionSize to set, starting from 0.
     */
    public void setLeftRegionSize(Integer leftRegionSize) {
        this.leftRegionSize = leftRegionSize;
    }

    /**
     * Returns current left region's width.
     * 
     * @return the leftRegionSize.
     */
    public Integer getLeftRegionSize() {
        // left region size should be smaller than cell's width or the default value is used
        if (leftRegionSize == null || leftRegionSize.intValue() > width) {
            leftRegionSize = Math.min(DEFAULT_LEFT_REGION_SIZE, width);
        }
        return leftRegionSize;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setOwnerTree(AbstractTreeGrid<M> ownerTree) {
        this.ownerTree = ownerTree;
    }

    /**
     * Sets a renderer for the left region. By default (ie. no renderer is specified), a renderer
     * {@link SimpleTextHtmlGridCellRenderer} is used.
     * 
     * @param leftRenderer
     *            the leftRenderer to set.
     */
    public void setLeftRenderer(HtmlGridCellRenderer<M> leftRenderer) {
        this.leftRenderer = leftRenderer;
    }

    /**
     * Sets a renderer for the right region. By default (ie. no renderer is specified), a renderer
     * {@link SimpleTextHtmlGridCellRenderer} is used.
     * 
     * @param rightRenderer
     *            the rightRenderer to set.
     */
    public void setRightRenderer(HtmlGridCellRenderer<M> rightRenderer) {
        this.rightRenderer = rightRenderer;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String render(M model, String property, ColumnData config, int rowIndex, int colIndex, ListStore<M> store,
            Grid<M> grid) {
        height = getHeight();
        width = getWidth();
        leftRegionSize = getLeftRegionSize();

        StringBuilder builder = new StringBuilder();
        String uniqueId = XDOM.getUniqueId();
        HtmlGridCellRenderer<M> renderer;

        // render border-layout container
        builder.append("<div id=\"").append(uniqueId).append("\" ");
        builder.append("class=\" x-component x-border-layout-ct\" ");
        builder.append("style=\"height: ").append(height).append("px; ").append("background: none;\"");
        builder.append(">");

        /*
         * render left component
         */

        String specialCssClassForCheckbox = "";
        renderer = getLeftRenderer();
        if (renderer instanceof CheckboxHtmlGridCellRenderer<?>) {
            specialCssClassForCheckbox = "x-form-check-wrap";
        }

        // render left component layout
        builder.append("<div class=\"" + specialCssClassForCheckbox + " x-form-field x-component x-border-panel\" ");
        builder.append("id=\"").append(uniqueId + "-left").append("\" ");
        builder.append("style=\"position: relative; left: 0px; top: 0px; ");
        builder.append("width: ").append(leftRegionSize).append("px; ");
        builder.append("height: ").append(height).append("px; ");
        builder.append("\">");

        // render left component
        if (leftRegionSize > 0) {
            renderer.setOwnerTree(ownerTree);

            String renderedText = (String) renderer.render(model, property, config, rowIndex, colIndex, store, grid);
            if (GwtStringUtils.isBlank(renderedText)) {
                renderedText = "&nbsp;";
            }
            builder.append(renderedText);
        }

        // close left component
        builder.append("</div>");

        /*
         * render right component
         */

        int rightCompLeft = leftRegionSize;
        int rightCompWidth = width - leftRegionSize;
        int remainingWidthInPercent = (int) ((float) rightCompWidth / width * MAX_PERCENTAGE_VALUE);

        specialCssClassForCheckbox = "";
        renderer = getRightRenderer();
        if (renderer instanceof CheckboxHtmlGridCellRenderer<?>) {
            specialCssClassForCheckbox = "x-form-check-wrap";
        }

        // render right component layout
        builder.append("<div class=\"" + specialCssClassForCheckbox + " x-form-field x-component x-border-panel\" ");
        builder.append("id=\"").append(uniqueId + "-right").append("\" ");
        builder.append("style=\"");
        builder.append("top: 0px; ");
        builder.append("left: ").append(rightCompLeft).append("px; ");
        builder.append("height: ").append(height).append("px; ");
        builder.append("width: " + remainingWidthInPercent + "%; ");
        builder.append("\">");

        // render right component
        if (rightCompWidth > 0) {
            renderer.setOwnerTree(ownerTree);

            String renderedText = (String) renderer.render(model, property, config, rowIndex, colIndex, store, grid);
            if (GwtStringUtils.isBlank(renderedText)) {
                renderedText = "&nbsp;";
            }
            builder.append(renderedText);
        }

        // close right component
        builder.append("</div>");

        // close container
        builder.append("</div>");

        return builder.toString();
    }

    /**
     * Renders left component renderer.
     * 
     * @return
     */
    protected HtmlGridCellRenderer<M> getLeftRenderer() {
        if (leftRenderer == null) {
            leftRenderer = new SimpleTextHtmlGridCellRenderer<M>(ownerColumn);
        }
        return leftRenderer;
    }

    /**
     * Renders right component renderer.
     * 
     * @return
     */
    protected HtmlGridCellRenderer<M> getRightRenderer() {
        if (rightRenderer == null) {
            rightRenderer = new SimpleTextHtmlGridCellRenderer<M>(ownerColumn);
        }
        return rightRenderer;
    }
}
